var InDConsole = function () {
    this.cssStyle = {
        'console': "position: absolute;opacity: 0.7;z-index: 9999;",
        'header-expand': "color: #ffffff;cursor: pointer;font-size: x-large;",
        'expand': "color: #333333;cursor: pointer;",
        'expand-triangle': "color: #666666;",
        'text': "color: #333333;",
        'name': "color: #990099;",
        'string': "color: #CC0033;",
        'number': "color: #3300CC;",
        'boolean': "color: #3300CC;",
        'null': "color: #3300CC;",
        'undefined': "color: #333333;",
        'object': "border-bottom: 1px solid #ddd;padding-top: 5px;padding-bottom: 5px;",
        'error': "background-color: #FFF0F0;color: #CC0033;",
        'warn': "background-color: #FFFBE5",
        'img': "position: absolute; left: 2px; width: 13px; height: 13px;"
    };
    this.settings = {
        fontSize: '16px',
        width: '100%'
    };
    this.codeRecord = '';  // 记录控制台输入的代码
};

// 初始化
InDConsole.prototype.init = function (dom, settings) {
    settings = settings || {};
    
    // 清空上一次的控制台输入代码记录
    this.codeRecord = '';

    // 保存设置
    this.settings.fontSize = settings.fontSize || this.settings.fontSize;
    this.settings.width = settings.width || this.settings.width;
    // 添加主元素
    var cssStyle = this.cssStyle;
    dom.innerHTML += '<div style="' + cssStyle['console'] + 'width:98%;height: 100%;overflow: auto;' + 'font-size:' + this.settings.fontSize + ';" class="InDConsole-main"><div class="InDConsole-container" style="width:98%"></div><div id="inputline"></div></div>';

    this.logContainer = document.getElementsByClassName('InDConsole-container')[0];
    this.addLastLine()
};
// Object.prototype.toString.call(object) === '[object Arguments]'
// 打印
InDConsole.prototype.clear = function () {
    this.logContainer.innerHTML = '';
}
InDConsole.prototype.render = function (object) {
    if (!this.logContainer) {
        // 未初始化
        console.log("未初始化");
        return
    }
    switch (object.type) {
        case 'log':
        case 'info':
        case 'debug':
            this.addNode(this.logContainer, null, object.data, true);
            break
        case 'error':
            this.addError(this.logContainer, null, object.data, true, '1');
            break
        case 'error2':
            this.addError(this.logContainer, null, object.data, true, '2');
            break
        case 'warn':
            this.addWarn(this.logContainer, null, object.data, true);
            break
        default:
            this.addNode(this.logContainer, null, object.data, true);
    }
    this.logContainer.lastElementChild.scrollIntoView()
};
InDConsole.prototype.addLastLine = function () {
    let ele = document.getElementById('inputline');
    ele.innerHTML += `
    <div style="display: flex;">
        <span style="color: #367CF1;line-height:35px">
            <icon class="el-icon-arrow-right"/>
        </span><div id="input" style="display:inline;outline:none;width:100%;padding: 0 6px;flex:1;line-height:32px" contenteditable="plaintext-only" onkeyup="document.sendCommand(this)"></div>
    </div>`;
    let inputEle = document.getElementById("input");
    inputEle.focus();
}
document.sendCommand = function (e) {
    var theEvent = window.event || e;
    var code = theEvent.keyCode || theEvent.which;
    if (code == 13) {
        // 获取可编辑div文本
        let text = e.innerText
        // 使用正则去掉文本前后的换行
        const code = text.replace(/^\n+|\n+$/g, '')
        let ele = document.getElementById('inputline')
        ele.removeChild(ele.lastElementChild);
        var runCode = inDConsole.codeRecord + 'return eval("' + code + '");';
        try{
            inDConsole.addInputNode(inDConsole.logContainer, code);
            inDConsole.addOutputNode(inDConsole.logContainer, new Function(runCode)());
            inDConsole.codeRecord = inDConsole.codeRecord + '' + code +';';
        } catch(err) {
            inDConsole.render({
                data: { msg: err },
                type: 'error2'
            })
        } finally {
            inDConsole.addLastLine()
        }
    }
}

InDConsole.prototype.addInputNode = function(parent, object) {
    parent.innerHTML += `
    <div style="display: flex;position: relative;border-bottom: 1px solid #ddd;">
        <span style="color: #939393; line-height: 35px;">
            <icon class="el-icon-arrow-right"/>
        </span><div style="display:inline;outline:none;width:100%;padding: 0 4px;flex:1;line-height:32px" contenteditable="plaintext-only" onkeyup="document.sendCommand(this)">${object}</div>
    </div>`
}

InDConsole.prototype.addOutputNode = function(parent, object) {
    parent.innerHTML += `
    <div style="display: flex;position: relative;border-bottom: 1px solid #ddd;">
        <span style="color: #BABABA; line-height:35px;position: absolute; left: 0">
            <icon class="el-icon-arrow-left"/>
        </span><div style="display:inline;outline:none;width:100%;padding: 0;flex:1;line-height:32px" contenteditable="plaintext-only" onkeyup="document.sendCommand(this)"></div>
    </div>`
    if (typeof object === 'object') {
        this.addNodeObject(parent.lastElementChild.lastElementChild, null, object);
    } else {
        this.addNodeBase(parent.lastElementChild.lastElementChild, null, object);
    }
}

InDConsole.prototype.addWarn = function (parent, name, object, isArgs=false) {
    var cssStyle = this.cssStyle;
    parent.innerHTML += `
    <div style="${cssStyle['warn']};position:relative;">
        <img src="../../static/pic/warn.svg" style="${cssStyle['img']};top: 10px" />
        <div><?div>
    </div>`
    this.addNode(parent.lastElementChild, null, object, isArgs);
}
InDConsole.prototype.addError = function (parent, name, object, isArgs=false ,type='1') {
    var cssStyle = this.cssStyle;
    if (type==='2') {
        parent.innerHTML += `
        <div style="${cssStyle['error']};padding:0 20px;position:relative;border-bottom: 1px solid #ddd;">
            <img src="../../static/pic/error.svg" style="${cssStyle['img']};top: 5px" />
            <div>
                ${object.msg.message}
            </div>
            <div style="display: flex;justify-content: flex-end;color: #545454">
                <p>${object.msg.filename||'about:srcdoc'}:</p>
                <p>${object.msg.lineno-object.linenum-82}</p>
            </div>
        </div>`;
    } else {
        parent.innerHTML += `
        <div style="${cssStyle['error']};position:relative;">
            <img src="../../static/pic/error.svg" style="${cssStyle['img']};top: 10px" />
            <div></div>
        </div>`
        this.addNode(parent.lastElementChild, null, object, isArgs);

    }

}

// 添加节点
InDConsole.prototype.addNode = function (parent, name, object, isArgs=false) {
    var cssStyle = this.cssStyle;
    parent.innerHTML += '<div style="' + cssStyle['object'] + '"></div>';
    if(isArgs){
        this.addArguments(parent.lastElementChild, name, object);
    } else if (typeof object === 'object') {
        this.addNodeObject(parent.lastElementChild, name, object);
    } else {
        this.addNodeBase(parent.lastElementChild, name, object);
    }
};

InDConsole.prototype.addArguments = function(parent, name, value) {
    // console.log(Object.prototype.toString.call(value),value)
    let args = Array.prototype.slice.apply(value)
    args.forEach(ele => {
        // console.log(Object.prototype.toString.call(ele),ele)
        switch(Object.prototype.toString.call(ele)){
            case "[object Array]":
            case "[object Object]":
                this.addNodeObject(parent, name, ele, true)
                break
            case "[object Function]":
                this.addNodeFunction(parent, name, ele)
                break
            case "[object Date]":
            case "[object RegExp]":
                this.addNodeBase(parent, name, ele)
                break
            default:
                this.addNodeBase(parent, name, ele)
        }
    })
}

InDConsole.prototype.addNodeFunction = function (parent, name, value) {
    var r = this.addNodeEmpty(parent, true);
    var rsInfo = this.getSpan(name, value, true, false);
    this.insallSpan(r.infoNode, rsInfo);
    var rsChild = this.getSpan(null, value.toString(), false, false, {
        enableQuotationMark: false
    });
    this.addNodeBase(r.childNode, null, rsChild.titleSpan);
}

// 添加基础节点。一个基础node由3部分组成：展开箭头，name和value。若不需要某一部分，传null即可
InDConsole.prototype.addNodeBase = function (parent, name, value) {
    var r = this.addNodeEmpty(parent, false);
    var rs = null;
    if(Object.prototype.toString.apply(value)==="[object Date]"||Object.prototype.toString.apply(value)==="[object RegExp]"){
        rs = this.getSpan(name, value.toString(), false, false, {
            enableQuotationMark: false
        });
    } else {
        rs = this.getSpan(name, value, false, false);
    }
   
    this.insallSpan(r.infoNode, rs);
};

// 添加一个空内容节点
InDConsole.prototype.addNodeEmpty = function (parent, enableExpand, isItalic=false) {
    // 是否使用斜体
    var innerHTML = '';
    var cssStyle = this.cssStyle;
    var margin = 16;
    // 允许展开，添加展开按钮
    if (enableExpand) {
        innerHTML = '<span style="' + cssStyle['expand'] + '" onclick="document.doExpand(this)"></span><div style="display:none;"></div>';
    } else {
        margin = 34;
    }
    parent.innerHTML += '<div style="'+ (isItalic?'font-style:italic;':'font-style:normal;') + 'margin-left: ' + margin +'px;">' + innerHTML + '</div>';

    var r = {
        infoNode: null,
        childNode: null
    };
    if (enableExpand) {
        r.infoNode = parent.lastElementChild.firstElementChild;
        r.childNode = parent.lastElementChild.lastElementChild;
    } else {
        r.infoNode = parent.lastElementChild;
    }
    return r;
};

// 根据node的属性获取内容span
InDConsole.prototype.getSpan = function (name, value, enableExpand, enableOmit, customStyle, isArray) {
    isArray = isArray || false;
    var rs = {
        expandSpan: null,
        nameSpan: null,
        titleSpan: null
    };

    customStyle = customStyle || {};
    var cssStyle = this.cssStyle;
    if (enableExpand) {
        rs.expandSpan = '<span style="' + cssStyle['expand-triangle'] + '">▶ </span>';
    }
    if (name || name === 0) {
        if (customStyle.nameStyle) {
            rs.nameSpan = '<span style="' + cssStyle[customStyle.nameStyle] + '">' + name + '</span>';
        } else {
            rs.nameSpan = '<span style="' + cssStyle.name + '">' + name + '</span>';
        }
    }

    var type = null;
    if (value === null) type = value = 'null';
    if (value === undefined) type = value = 'undefined';
    if (!type) type = typeof (value);
    if (type === 'function') {
        var strF = value.toString();
        var param = strF.substring(strF.indexOf('(') + 1, strF.indexOf(')'));
        rs.titleSpan = '<span><i style="color:blue;">f</i> (' + param + ')</span>';
    } else {
        if (enableOmit) {
            value = '' + value;
            if (value.length > 20) value = value.substring(0, 20) + '...';
        }

        var destStyle = (customStyle.titleStyle) ? customStyle.titleStyle : type;
        if (name&&!isArray) {
            // 对于有name属性的可展开节点，展开时，允许隐藏title
            rs.titleSpan = '<span class="enable-hide" style="' + cssStyle[destStyle] + '">' + value + '</span>';
        } else {
            rs.titleSpan = '<span style="' + cssStyle[destStyle] + '">' + value + '</span>';
        }

        // 是否添加引号
        if (customStyle.enableQuotationMark != undefined) {
            if (customStyle.enableQuotationMark) {
                rs.titleSpan = '\"' + rs.titleSpan + '\"';
            }
        } else {
            if (type === 'string') {
                rs.titleSpan = '\"' + rs.titleSpan + '\"';
            }
        }
    }

    return rs;
};

// 为一个节点添加内容
InDConsole.prototype.insallSpan = function (parent, rs) {
    var innerHTML = '';
    if (rs.expandSpan) innerHTML += rs.expandSpan;
    if (rs.nameSpan) innerHTML += rs.nameSpan;
    if (rs.nameSpan && rs.titleSpan) innerHTML += " : ";
    if (rs.titleSpan) innerHTML += rs.titleSpan;

    parent.innerHTML = innerHTML;
};

// 添加Object节点。Object节点前可能有name，也可能没有
InDConsole.prototype.addNodeObject = function (parent, name, object, isItalic=false) {
    if (object === null) {
        // 若Object为null，则直接添加一个null节点
        return this.addNodeBase(parent, name, object);
    }

    // Object不为null，则添加一个带有expand的节点作为Object节点，然后填充内容
    var r = this.addNodeEmpty(parent, true, isItalic);
    var title = this.getObjectTitle(name, object);
    var rs = this.getSpan(name, title, true, false, {
        titleStyle: 'text',
        enableQuotationMark: false
    });
    this.insallSpan(r.infoNode, rs);

    var child = r.childNode;

    if (Object.prototype.toString.call(object) === '[object Array]') {
        for(let k in object){
            switch(Object.prototype.toString.call(object[k])){
                case "[object Array]":
                case "[object Object]":
                    this.addNodeObject(child, k, object[k]);
                    break
                case "[object Function]":
                    this.addNodeFunction(child, k, object[k]);
                    break
                case "[object Date]":
                    this.addNodeBase(child, k, object[k].toString());
                    break
                default:
                    this.addNodeBase(child, k, object[k]);
            }
        }
        return
    }

    for (var attr in object) {
        var cObject = object[attr];
        switch(Object.prototype.toString.call(cObject)){
            case "[object Array]":
            case "[object Object]":
                this.addNodeObject(child, attr, cObject);
                break
            case "[object Function]":
                this.addNodeFunction(child, attr, cObject);
                break
            case "[object Date]":
                this.addNodeBase(child, attr, cObject.toString());
                break
            default:
                this.addNodeBase(child, attr, cObject);
        }
    }
};

// 获取object的title
InDConsole.prototype.getObjectTitle = function (name, object) {
    let title = '';
    switch(Object.prototype.toString.call(object)){
        case '[object Array]':
            title = `(${object.length}) [ `;
            var index = 0;
            for (let k in object) {
                if (title.length > 1024) {
                    title += "..., ";
                    break;
                }
                var kIsNum = Number(k)===index;
                index ++;
                switch(Object.prototype.toString.apply(object[k])){
                    case "[object Array]":
                        title += kIsNum ? `Array(${object[k].length}), ` : `${ k } : Array(${object[k].length}), `;
                        break;
                    case "[object Object]":
                        title += kIsNum ? `{...}, ` : `${ k } : {...}, `;
                        break;
                    case "[object Function]":
                        var rs = this.getSpan(k, object[k], true, true, {
                            nameStyle: 'text'
                        }, true);
                        title += kIsNum ? `${rs.titleSpan}, ` : `${rs.nameSpan} : ${rs.titleSpan}, `;
                        break;
                    default:
                        var rs = this.getSpan(k, object[k], false, true, {
                            nameStyle: 'text'
                        }, true);
                        title += kIsNum ? `${rs.titleSpan}, ` : `${rs.nameSpan} : ${rs.titleSpan}, `;
                }
            }
            if (object.length !== 0) {
                title = title.substring(0, title.length - 2)
            }
            title = title + ']';
            break;
        case '[object Object]':
            title = '{';
            for (let attr in object) {
                if (title.length > 512) {
                    title += "..., ";
                    break;
                }
                
                let cObject = object[attr];
                switch(Object.prototype.toString.apply(cObject)){
                    case "[object Array]":
                        title += attr + ` : Array(${cObject.length}), `;
                        break;
                    case "[object Object]":
                        title += attr + ' : {...}, ';
                        break;
                    case "[object Function]":
                        var rs = this.getSpan(attr, cObject, true, false, {
                            nameStyle: 'text'
                        });
                        title += rs.nameSpan + " : " + rs.titleSpan + ", ";
                        break;
                    default:
                        var rs = this.getSpan(attr, cObject, false, true, {
                            nameStyle: 'text'
                        });
                        title += rs.nameSpan + " : " + rs.titleSpan + ", ";
                }
            }
            if (JSON.stringify(object) !== '{}') {
                // 这里要删除title最后一个，号及一个空格，共2个字符
                title = title.substring(0, title.length - 2);
            }
            // 这里要删除title最后一个，号及一个空格，共2个字符
            title = title + '}';
            break;
    }
    return title;
};

// 展开/收起
document.doExpand = function (object) {
    var title = object.textContent.replace(/(^\s*)|(\s*$)/g, "");
    if (title.indexOf('▼') == 0) {
        object.innerHTML = object.innerHTML.replace(/▼/, '▶');
        object.parentNode.lastElementChild.style.display = 'none';
        // 对于允许隐藏title的，展开时将title隐藏，收起时将title显示
        var es = object.getElementsByClassName("enable-hide");
        if (es.length > 0) {
            es[0].style.display = '';
        }
    } else {
        // object.parentNode.style['margin-left'] = 0;
        object.innerHTML = object.innerHTML.replace(/▶/, '▼');
        object.parentNode.lastElementChild.style.display = 'block';
        // 对于允许隐藏title的，展开时将title隐藏，收起时将title显示
        var es = object.getElementsByClassName("enable-hide");
        if (es.length > 0) {
            es[0].style.display = 'none';
        }
    }
};

const inDConsole = new InDConsole();

// Vue将下面export放开
export default inDConsole;

// 说明
/***
导入
1.常规web：
引入InDConsole.js，然后new对象：
var InDConsole = new InDConsole();
初始化：
InDConsole.init({
width: 500,
headerHeight: 30,
bodyHeight: 600,
headerBKColor: '#666666',
bodyBKColor: '#eeeeee',
fontSize: '16px'
});
安装拖动功能：
InDConsole.installWebDrag();
2.Vue: 放开本js代码末尾关于Vue的一行，然后导入：
import { InDConsole } from './InDConsole'
初始化：
export default {
mounted() {
  InDConsole.init({
    width: 500,
    headerHeight: 30,
    bodyHeight: 600,
    headerBKColor: '#666666',
    bodyBKColor: '#eeeeee',
    fontSize: '16px'
  });
}
}
使用
InDConsole.log(object);
// 拖动功能只有PC端可用。移动端无法使用
***/